import selectors
import threading
import socket
import logging

FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)


class HTTPServer:
    def __init__(self, ip='127.0.0.1', port=80):
        self.laddr = (ip, port)
        self.sock = socket.socket()
        self.sock.bind(self.laddr)
        self.sock.listen()
        self.sock.setblocking(False)
        self.selector = selectors.DefaultSelector()
        self.event = threading.Event()
        self.index = 'index.html'

    def __accept(self, sock:socket.socket, mask):
        client, raddr = sock.accept()
        logging.info('IN ACCEPT client: {} {}:{}'.format(client, *raddr))
        _ = self.selector.register(client, selectors.EVENT_READ, self.__recv)

    def __recv(self, sock:socket.socket, mask):
        try:
            data = sock.recv(1024).decode()
            res = data.split(' ')[1]
            response = self.router(res)
            sock.send(response)
        except Exception:
            pass
        finally:
            sock.close()
            self.selector.unregister(sock)

    def router(self, res):
        if res == '/':
            response = self.response(self.index)
        else:
            response = "<html><head>404 Not Found</head></html>"
        return response

    def response(self, filename):
        with open(filename, 'rb') as f:
            res = f.read()
        return res

    def start(self):
        key = self.selector.register(self.sock, selectors.EVENT_READ, self.__accept)
        logging.info('IN START Conn: {}'.format(key))

        while not self.event.is_set():
            events = self.selector.select()
            for key, mask in events:
                callback = key.data
                callback(key.fileobj, mask)

    def stop(self):
        self.event.set()
        self.event.wait(2)
        self.sock.close()


def main():
    hs = HTTPServer()
    threading.Thread(target=hs.start, name='HTTPServer', daemon=True).start()
    while True:
        cmd = input('>>> ').strip()
        if cmd == 'quit':
            hs.stop()
            break
        print(threading.enumerate())


if __name__ == '__main__':
    with open('index.html', 'rb') as f:
        res = f.read()
        print(res)

    main()
